package com.atguigu.gulimall.ware.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.to.OrderTo;
import com.atguigu.common.utils.R;
import com.atguigu.common.vo.HasStockVo;
import com.atguigu.gulimall.ware.entity.WareOrderTaskDetailEntity;
import com.atguigu.gulimall.ware.entity.WareOrderTaskEntity;
import com.atguigu.gulimall.ware.enume.OrderStatusEnum;
import com.atguigu.gulimall.ware.exception.NoStockException;
import com.atguigu.gulimall.ware.feign.OrderFeign;
import com.atguigu.gulimall.ware.feign.SkuInfoService;
import com.atguigu.gulimall.ware.service.WareOrderTaskDetailService;
import com.atguigu.gulimall.ware.service.WareOrderTaskService;
import com.atguigu.gulimall.ware.vo.*;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.Query;

import com.atguigu.gulimall.ware.dao.WareSkuDao;
import com.atguigu.gulimall.ware.entity.WareSkuEntity;
import com.atguigu.gulimall.ware.service.WareSkuService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;


@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> implements WareSkuService {
    @Autowired
    private SkuInfoService skuInfoService;
    @Autowired
    private WareOrderTaskService wareOrderTaskService;
    @Autowired
    private WareOrderTaskDetailService wareOrderTaskDetailService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private OrderFeign orderFeign;
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                new QueryWrapper<WareSkuEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public PageUtils queryByCondition(Map<String, Object> params) {
        String skuId = (String) params.get("skuId");
        String wareId = (String) params.get("wareId");
        QueryWrapper<WareSkuEntity> queryWrapper = new QueryWrapper<>();
        if(!StringUtils.isEmpty(skuId)){
            queryWrapper.eq("sku_id",skuId);
        }
        if(!StringUtils.isEmpty(wareId)){
            queryWrapper.eq("ware_id",wareId);
        }
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

    @Override
    public void addToWare(Long skuId, Long wareId, Integer skuNum) {
        WareSkuEntity wareSkuEntity = this.getOne(new QueryWrapper<WareSkuEntity>().eq("sku_id", skuId).eq("ware_id", wareId));
        if(wareSkuEntity!=null){
            wareSkuEntity.setStock(wareSkuEntity.getStock()+skuNum);
            this.updateById(wareSkuEntity);
        }else {
            wareSkuEntity = new WareSkuEntity();
            wareSkuEntity.setSkuId(skuId);
            wareSkuEntity.setWareId(wareId);
            wareSkuEntity.setStock(skuNum);
            R r = skuInfoService.info(skuId);
            Map<String,Object> map = (Map<String,Object>) r.get("skuInfo");
            wareSkuEntity.setSkuName(map.get("skuName").toString());
            this.save(wareSkuEntity);
        }
    }

    @Override
    public List<HasStockVo> hasStock(List<Long> skuIds) {
        List<HasStockVo> hasStockVoList = skuIds.stream().map(skuId -> {
            WareSkuEntity wareSkuEntity = this.getOne(new QueryWrapper<WareSkuEntity>().eq("sku_id", skuId));
            return wareSkuEntity;
        }).filter(wareSkuEntity -> {
            if(wareSkuEntity==null){
                return false;
            }
            return Integer.compare(wareSkuEntity.getStock(), wareSkuEntity.getStockLocked()) > 0;
        }).map(wareSkuEntity -> {
            HasStockVo hasStockVo = new HasStockVo();
            hasStockVo.setSkuId(wareSkuEntity.getSkuId());
            hasStockVo.setHasStock(true);
            return hasStockVo;
        }).collect(Collectors.toList());
        return hasStockVoList;
    }

    @Override
    public List<HasStockVo> getHasStock(List<Long> skuIds) {
        List<HasStockVo> hasStockVos = skuIds.stream().map(skuId -> {
            Long count = this.baseMapper.getHasStock(skuId);
            HasStockVo hasStockVo = new HasStockVo();
            hasStockVo.setSkuId(skuId);
            hasStockVo.setHasStock(count == null ? false : count > 0);
            return hasStockVo;
        }).collect(Collectors.toList());
        return hasStockVos;
    }

    @Override
    @Transactional
    public void lockStock(LockStockVo lockStockVo) throws NoStockException{

        WareOrderTaskEntity wareOrderTaskEntity = new WareOrderTaskEntity();
        wareOrderTaskEntity.setCreateTime(new Date());
        wareOrderTaskEntity.setOrderSn(lockStockVo.getOrderSn());
        wareOrderTaskService.save(wareOrderTaskEntity);

        //查询有库存的仓库id
        List<StockVo> stockVos = lockStockVo.getOrderItemVoList().stream().map(item -> {
            StockVo stockVo = new StockVo();
            List<Long> wareIds = this.baseMapper.getHasStockWareIds(item.getSkuId());
            stockVo.setWareIds(wareIds);
            stockVo.setAmount(item.getAmount());
            stockVo.setSkuId(item.getSkuId());
            return stockVo;
        }).collect(Collectors.toList());
        //锁定库存
        for (StockVo stockVo : stockVos) {
            Boolean noStock = true;
            if(stockVo.getWareIds()==null){
                throw new NoStockException(stockVo.getSkuId());
            }
            for (Long wareId : stockVo.getWareIds()) {
                Long count = this.baseMapper.lockStock(wareId,stockVo.getSkuId(),stockVo.getAmount());
                if(count==1){
                    noStock = false;
                    WareOrderTaskDetailEntity wareOrderTaskDetailEntity = new WareOrderTaskDetailEntity();
                    wareOrderTaskDetailEntity.setLockStatus(1);
                    wareOrderTaskDetailEntity.setSkuId(stockVo.getSkuId());
                    wareOrderTaskDetailEntity.setSkuName("");
                    wareOrderTaskDetailEntity.setTaskId(wareOrderTaskEntity.getId());
                    wareOrderTaskDetailEntity.setWareId(wareId);
                    wareOrderTaskDetailEntity.setSkuNum(stockVo.getAmount());
                    wareOrderTaskDetailService.save(wareOrderTaskDetailEntity);
                    //没锁定一条库存给rabiitMq发送一条消息
                    LockStockRabbitMqVo lockStockRabbitMqVo = new LockStockRabbitMqVo();
                    lockStockRabbitMqVo.setTaskId(wareOrderTaskEntity.getId());
                    lockStockRabbitMqVo.setDetailEntity(wareOrderTaskDetailEntity);

                    rabbitTemplate.convertAndSend("stock-event-exchange","stock.lock",lockStockRabbitMqVo);
                    break;
                }
            }
            if(noStock){
                throw new NoStockException(stockVo.getSkuId());
            }
        }
    }

    @Override
    public void unLock(LockStockRabbitMqVo lockStockRabbitMqVo) {
        Long taskId = lockStockRabbitMqVo.getTaskId();
        WareOrderTaskDetailEntity detailEntity = lockStockRabbitMqVo.getDetailEntity();
        //实时查出detailEntity的解锁状态
        WareOrderTaskDetailEntity byId = wareOrderTaskDetailService.getById(detailEntity.getId());
        WareOrderTaskEntity taskEntity = wareOrderTaskService.getById(taskId);

        if(byId!=null){
            String orderSn = taskEntity.getOrderSn();
            R r = orderFeign.getOrderEntityByOrderSn(orderSn);
            OrderEntity data = r.getData("data", new TypeReference<OrderEntity>() {});
            if(r.getCode()==0){

                if(data==null ||data.getStatus()==OrderStatusEnum.CANCLED.getCode() ){
                    if(byId.getLockStatus()==1){
                        this.unLockStock(byId.getSkuId(),byId.getSkuNum(),byId.getWareId(),byId.getId());
                    }else {
                        //已经解锁，无需解锁
                    }
                }else{
                    //已经付款，无需解锁
                }

            }else {
                //重新返回队列
            }
        }else {
            //库存自己回滚，无需解锁
        }
    }

    @Override
    public void unLockStock(Long skuId, Integer skuNum, Long wareId, Long id) {
        this.baseMapper.unLockStock(skuId,skuNum,wareId);

        WareOrderTaskDetailEntity wareOrderTaskDetailEntity = new WareOrderTaskDetailEntity();
        wareOrderTaskDetailEntity.setId(id);
        //2=》已解锁
        wareOrderTaskDetailEntity.setLockStatus(2);
        wareOrderTaskDetailService.updateById(wareOrderTaskDetailEntity);
    }

    @Override
    public void unLock(OrderTo orderTo) {
        String orderSn = orderTo.getOrderSn();
        WareOrderTaskEntity wareOrderTaskEntity = wareOrderTaskService.getOne(new QueryWrapper<WareOrderTaskEntity>().eq("order_sn", orderTo.getOrderSn()));
        Long taskEntityId = wareOrderTaskEntity.getId();
        List<WareOrderTaskDetailEntity> detailEntityList = wareOrderTaskDetailService.list(new QueryWrapper<WareOrderTaskDetailEntity>().eq("task_id", taskEntityId)
                                                            .eq("lock_status",1));


        if(detailEntityList!=null){
            for (WareOrderTaskDetailEntity entity : detailEntityList) {
                unLockStock(entity.getSkuId(),entity.getSkuNum(),entity.getWareId(),entity.getId());
            }
        }
    }

}